home *** CD-ROM | disk | FTP | other *** search
/ Aminet 31 / Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso / Aminet / dev / c / random.lha / random / random-c / random.c < prev    next >
C/C++ Source or Header  |  1999-02-28  |  5KB  |  325 lines

  1. /*
  2.  
  3. C This random number generator originally appeared in "Toward a Universal 
  4.  
  5. C Random Number Generator" by George Marsaglia and Arif Zaman. 
  6.  
  7. C Florida State University Report: FSU-SCRI-87-50 (1987)
  8.  
  9.  
  10. C It was later modified by F. James and published in "A Review of Pseudo-
  11.  
  12. C random Number Generators" 
  13.  
  14.  
  15. C THIS IS THE BEST KNOWN RANDOM NUMBER GENERATOR AVAILABLE.
  16.  
  17. C       (However, a newly discovered technique can yield 
  18.  
  19. C         a period of 10^600. But that is still in the development stage.)
  20.  
  21. C
  22.  
  23. C It passes ALL of the tests for random number generators and has a period 
  24.  
  25. C   of 2^144, is completely portable (gives bit identical results on all 
  26.  
  27. C   machines with at least 24-bit mantissas in the floating point 
  28.  
  29. C   representation). 
  30.  
  31.  
  32. C The algorithm is a combination of a Fibonacci sequence (with lags of 97
  33.  
  34. C   and 33, and operation "subtraction plus one, modulo one") and an 
  35.  
  36. C   "arithmetic sequence" (using subtraction).
  37.  
  38. C======================================================================== 
  39.  
  40. This C language version was written by Jim Butler, and was based on a
  41.  
  42. FORTRAN program posted by David LaSalle of Florida State University.
  43.  
  44. */
  45.  
  46.  
  47.  
  48. #include <stdio.h>
  49.  
  50. #include <stdlib.h>
  51.  
  52.  
  53.  
  54. #define TRUE -1
  55.  
  56. #define FALSE 0
  57.  
  58. #define boolean int
  59.  
  60.  
  61.  
  62. static void rmarin(int ij, int kl);
  63.  
  64. void ranmar(float rvec[], int len);
  65.  
  66.  
  67.  
  68. void main()
  69.  
  70. {
  71.  
  72.     float temp[101];
  73.  
  74.     int ij, kl, len, i;
  75.  
  76.  
  77.  
  78.     /* random seeds for the test case: */
  79.  
  80.     ij = 1802;
  81.  
  82.     kl = 9373;
  83.  
  84.  
  85.  
  86.     /* do the initialization */
  87.  
  88.     rmarin(ij,kl);
  89.  
  90.     
  91.  
  92.     /* generate 20,000 random numbers */
  93.  
  94.     len = 100;
  95.  
  96.     for (i=1; i<=200; i++)
  97.  
  98.         ranmar(temp, len);
  99.  
  100.         
  101.  
  102. /*
  103.  
  104. C If the random number generator is working properly, the next six random
  105.  
  106. C numbers should be:
  107.  
  108. C           6533892.0  14220222.0  7275067.0
  109.  
  110. C           6172232.0  8354498.0   10633180.0
  111.  
  112. */
  113.  
  114.      len = 6;
  115.  
  116.      ranmar(temp,len);
  117.  
  118.      
  119.  
  120.      for (i=1; i<=6; i++)
  121.  
  122.          printf("%12.1f ", 4096.0*4096.0*temp[i]);
  123.  
  124. }
  125.  
  126.  
  127.  
  128. static float u[98], c, cd, cm;
  129.  
  130. static int i97, j97;
  131.  
  132. static boolean test = FALSE;
  133.  
  134.  
  135.  
  136. static void rmarin(ij,kl)
  137.  
  138. int ij, kl;
  139.  
  140. {
  141.  
  142. /*
  143.  
  144. C This is the initialization routine for the random number generator RANMAR()
  145.  
  146. C NOTE: The seed variables can have values between:    0 <= IJ <= 31328
  147.  
  148. C                                                      0 <= KL <= 30081
  149.  
  150. C The random number sequences created by these two seeds are of sufficient 
  151.  
  152. C length to complete an entire calculation with. For example, if sveral 
  153.  
  154. C different groups are working on different parts of the same calculation,
  155.  
  156. C each group could be assigned its own IJ seed. This would leave each group
  157.  
  158. C with 30000 choices for the second seed. That is to say, this random 
  159.  
  160. C number generator can create 900 million different subsequences -- with 
  161.  
  162. C each subsequence having a length of approximately 10^30.
  163.  
  164.  
  165. C Use IJ = 1802 & KL = 9373 to test the random number generator. The
  166.  
  167. C subroutine RANMAR should be used to generate 20000 random numbers.
  168.  
  169. C Then display the next six random numbers generated multiplied by 4096*4096
  170.  
  171. C If the random number generator is working properly, the random numbers
  172.  
  173. C should be:
  174.  
  175. C           6533892.0  14220222.0  7275067.0
  176.  
  177. C           6172232.0  8354498.0   10633180.0
  178.  
  179. */
  180.  
  181.     int i, j, k, l, ii, jj, m;
  182.  
  183.     float s, t;
  184.  
  185.     
  186.  
  187.     if (ij<0 || ij>31328 || kl<0 || kl>30081) {
  188.  
  189.         puts("The first random number seed must have a value between 0 and 31328.");
  190.  
  191.         puts("The second seed must have a value between 0 and 30081.");
  192.  
  193.         exit(1);
  194.  
  195.     }
  196.  
  197.     
  198.  
  199.     i = (ij/177)%177 + 2;
  200.  
  201.     j = ij%177 + 2;
  202.  
  203.     k = (kl/169)%178 + 1;
  204.  
  205.     l = kl%169;
  206.  
  207.     
  208.  
  209.     for (ii=1; ii<=97; ii++) {
  210.  
  211.         s = 0.0;
  212.  
  213.         t = 0.5;
  214.  
  215.         for (jj=1; jj<=24; jj++) {
  216.  
  217.             m = (((i*j)%179)*k) % 179;
  218.  
  219.             i = j;
  220.  
  221.             j = k;
  222.  
  223.             k = m;
  224.  
  225.             l = (53*l + 1) % 169;
  226.  
  227.             if ((l*m)%64 >= 32) s += t;
  228.  
  229.             t *= 0.5;
  230.  
  231.         }
  232.  
  233.         u[ii] = s;
  234.  
  235.     }
  236.  
  237.     
  238.  
  239.     c = 362436.0 / 16777216.0;
  240.  
  241.     cd = 7654321.0 / 16777216.0;
  242.  
  243.     cm = 16777213.0 / 16777216.0;
  244.  
  245.     
  246.  
  247.     i97 = 97;
  248.  
  249.     j97 = 33;
  250.  
  251.     
  252.  
  253.     test = TRUE;
  254.  
  255. }
  256.  
  257.  
  258.  
  259. void ranmar(rvec, len)
  260.  
  261. float rvec[];    /* len random numbers are placed in rvec[1..len] */
  262.  
  263. int len;
  264.  
  265. /*
  266.  
  267. C This is the random number generator proposed by George Marsaglia in 
  268.  
  269. C Florida State University Report: FSU-SCRI-87-50
  270.  
  271. C It was slightly modified by F. James to produce an array of pseudorandom
  272.  
  273. C numbers.
  274.  
  275. */
  276.  
  277. {
  278.  
  279.     int ivec;
  280.  
  281.     float uni;
  282.  
  283.     
  284.  
  285.     if (test==FALSE) {
  286.  
  287.         puts("Call the init routine rmarin() before calling ranmar().");
  288.  
  289.         exit(2);
  290.  
  291.     }
  292.  
  293.     for (ivec=1; ivec<=len; ivec++) {
  294.  
  295.         uni = u[i97] - u[j97];
  296.  
  297.         if (uni < 0.0) uni += 1.0;
  298.  
  299.         u[i97] = uni;
  300.  
  301.         i97--;
  302.  
  303.         if (i97==0) i97 = 97;
  304.  
  305.         j97--;
  306.  
  307.         if (j97==0) j97 = 97;
  308.  
  309.         c -= cd;
  310.  
  311.         if (c<0.0) c += cm;
  312.  
  313.         uni -= c;
  314.  
  315.         if (uni<0.0) uni += 1.0;
  316.  
  317.         rvec[ivec] = uni;
  318.  
  319.     }
  320.  
  321. }